/*
 * Blocksort.h
 *
 *  Created on: May 21, 2012
 *      Author: Nico
 */
typedef struct{
	char* caracter;
	uInt indice;
}caracterIndice;

bool cmpCaracterIndice(caracterIndice a, caracterIndice b){
	// Comparo lexicograficamente (comparo ASCII)
	if( *(a.caracter) < *(b.caracter) ) return true;
	
	// Comparo lexicograficamente (comparo ASCII)
	if( *(a.caracter) > *(b.caracter) ) return false;
	
	// Comparo numeros
	if( (a.indice) < (b.indice) ) return true;
	
	return false;
}

class Blocksort{
	
	
	protected:
		/* Atributos protegidos */
		
		// Tamanio del bloque en Bytes
		uInt blockSize;
		
		// Nombre del archivo de entrada
		char* inputFilename;
		
		
		// Nombre del archivo donde se guardara la salida
		char* outputFilename;
		
		
		// Indica si se esta leyendo desde archivo o analizando un 
		// bloque pasado por codigo.
		bool readingFromFile;
		

		
	public:

		
		/* Atributos publicos */
		
		// Si esta prendido, muestra debugs por pantalla
		bool debug; 
		
		
		/* Metodos publicos */
		
		void setInputFilename(const char*);
		void setOutputFilename(const char*);

};



class BlocksortCompress : public Blocksort{
	/* Member functions */
	// Ref1: http://en.wikipedia.org/wiki/C%2B%2B_classes#Member_functions
	// Ref2: http://tipsandtricks.runicsoft.com/Cpp/Sort.html
	typedef struct{
		char* indexStart;
		char* indexEnd;
	}parOrdenado;
	
	struct sortParOrdenado{
	
		BlocksortCompress* m;
		sortParOrdenado(BlocksortCompress* p) : m(p) {};
		
		bool operator() (const parOrdenado* a , const parOrdenado* b ){
			return m->cmpParOrdenado(a,b);
		}
	};
	
	private:
		bool imAtFirstBlock;
		
		void init();
		
	protected:
		/* Atributos protegidos */
		
		ifstream inputFile;
		
		//ofstream outputFile;
		OCompressedStream* outputFile;
		
		// Indica la cantidad de bytes que se leyeron en la ultima
		// lectura. Sirve para saber cuantos bytes fueron leidos
		// en la lectura justo anterior al EOF. Cuando no hubo EOF, el
		// valor de lastReadSize sera igual a blockSize
		uInt lastReadSize;
		
		// Guardo las posiciones de memoria del primer y ultimo byte
		// del bloque de memoria leido. Me sirve para armar las rotaciones.
		char* blockFirstChar;
		char* blockLastChar;
	
	
	
	
		/* Metodos protegidos */
		

		
		// Trae un bloque de texto del archivo de entrada
		int getNextBlockOfText(char**);
		
		// Genera la matriz M (Algoritmo C)
		void spinText( const char* texto , vector<parOrdenado*>* );

		// Obtiene indice I y vector L (Algoritmo C)
		void findLandI( /* const */ vector<parOrdenado*>*, string* L , uInt* I );
		
		// Funcion para comparar si un par ordenado es mayor que otro
		// (Compara el texto en memoria)
		bool cmpParOrdenado(const parOrdenado *a, const parOrdenado *b);
				
		// Solo para debug, interpreta un par ordenado imprimiendo su 
		// string correspondiente
		void debug_parOrdenado(parOrdenado*);
		
	public:
	
		// Dos constructores, por si se quiere usar con o sin archivos
		BlocksortCompress();
		BlocksortCompress(const char* inputFilename , const int blockSize);

		// Destructor
		~BlocksortCompress();
		
		// Aplica blocksorting a un bloque del archivo de entrada y
		// guarda el resultado en el archivo de output
		int runNextBlock( string* L, uInt* I );
		
		// Aplica blocksorting a un texto pasado por parametro
		int runBlock(const char* texto , string* L, uInt* I );
		
		// Comprime todo el archivo
		int run();
};


class BlocksortDecompress : public Blocksort{
	
	protected:
		ICompressedStream* inputFile;
		
		ofstream outputFile;

		
	public:
	
		BlocksortDecompress(const char* inputFilename);
		
		// Destructor
		~BlocksortDecompress();
		
		
		// "Descomprime" un bloque del archivo de entrada y
		// guarda el resultado en el archivo de output
		int runNextBlock( string* texto );
		
		// "Descomprime" un bloque comprimido con blocksort
		static int runBlock( const char* L, const uInt I , const uInt blockLength , string* texto );
		
		
		// Descomprime todo el archivo.
		int run();
};
